//	Project:	HexTower
//	File:		DirectInput_Manager.h
//	Author:		Mustafa Aldoori
//	Purpose:	Direct Input Manager to handle all input devices.

#pragma once

//	The version of DirectInput to use.
#ifndef DIRECTINPUT_VERSION
	#define DIRECTINPUT_VERSION 0X800
#endif

#include <dinput.h>
#include "UtilityManager.h"
#include <tchar.h>
#include <vector>
using std::vector;

#pragma comment(lib, "dinput8.lib")
#pragma comment(lib, "dxguid.lib")

//	Forward declarations:
class DIKeyboard;
class DIMouse;
class DIJoystick;

enum DeviceFlags	{ DI_KEYBOARD = 1, DI_MOUSE = 2, DI_JOYSTICKS = 4 };
enum Directions		{ DIR_LEFT = 0, DIR_RIGHT = 1, DIR_UP = 2, DIR_DOWN = 3, DIR_MAX };
enum MouseButtons	{ MOUSE_LEFT = 0, MOUSE_RIGHT = 1, MOUSE_MIDDLE = 2, MOUSE_MAX };

class DirectInput_Manager
{
private:
	LPDIRECTINPUT8				m_lpDIObject;
	
	DIKeyboard*					m_pKeyboard;	//	Keyboard object
	DIMouse*					m_pMouse;		//	Mouse object
	vector< DIJoystick* >		m_vpJoysticks;	//	Joysticks objects

	// Utility struct for joystick setup:
	struct tJoystickSetupInfo
	{
		HWND hWnd;
		bool bIsExclusive;
	};

	// Singleton
	static DirectInput_Manager	m_Instance;

	// Trilogy of Evil
	DirectInput_Manager( void );
	DirectInput_Manager( const DirectInput_Manager& );
	DirectInput_Manager& operator=( const DirectInput_Manager& );
	~DirectInput_Manager( void );

	//	Return	:	true if it was able to initialize the Keyboard.
	//	Purpose	:	Initialize the Keyboard for DirectInput.
	bool InitKeyboard( HWND hWnd, bool bIsExclusive = false );

	//	Return	:	true if it was able to initialize the Mouse.
	//	Purpose	:	Initialize the Mouse for DirectInput.
	bool InitMouse( HWND hWnd, bool bIsExclusive = false );

	//	Return	:	true if it was able to initialize the joysticks.
	//	Purpose	:	Initialize the joysticks for DirectInput.
	bool InitJoysticks( HWND hWnd, bool bIsExclusive = false );

	//	Return	:	Returns after all of the joysticks connected to the computer have been found.
	//	Purpose	:	Checks to see if there are any Joysticks presently attached to the computer.
	static BOOL CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* lpdidi, VOID* pVoid );

public:

	//	Singleton GetInstance
	static DirectInput_Manager* GetInstance(void);

	//	Purpose	:	To initialize the DirectInput Object and requested devices.
	bool InitDirectInput(HWND hWnd, HINSTANCE hInstance, unsigned int unInitDevices, unsigned int unExclusiveDevices = 0);

	//	Purpose:	Shuts down DirectInput and any initialized devices.
	void ShutdownDirectInput(void);

	//	Purpose	:	Gets the state of all the initialized devices.
	//				Reads buffered data as well (for Ex functions).
	void ReadDevices(void);

	//	Purpose	:	Clears out the input for all the initialized devices.
	void ClearInput(void);

	//	Purpose	:	Acquires all the initialized direct input devices (i.e. keyboard, mouse, and joysticks).
	//				Ideally called when the application gains focus.
	void AcquireAll(void);

	//	Purpose	:	Unacquires all the initialized direct input devices (i.e. keyboard, mouse, and joysticks).
	//				Ideally called when the application loses focus.
	void UnacquireAll(void);

	/***********************	Device specific functions:	********************/

	///////////////////////////////////////////////////////////////////
	//						KEYBOARD								 //
	///////////////////////////////////////////////////////////////////

	//	Purpose	:	Gets the current (immediate) state of a Key.
	bool KeyDown(unsigned char ucDIKey);
	
	//	Purpose	:	To tell if a key was just pressed (without using DirectInput's Buffered Input).
	bool KeyPressed(unsigned char ucDIKey);

	//	Purpose	:	To tell if a key was just pressed (using DirectInput's Buffered Input).
	bool KeyPressedEx(unsigned char ucDIKey);

	//	Purpose	:	Gets the current (immediate) state of a Key.
	bool KeyUp(unsigned char ucDIKey);
	
	//	Purpose	:	To tell if a key was just released (without using DirectInput's Buffered Input).
	bool KeyReleased(unsigned char ucDIKey);

	//	Purpose	:	To tell if a key was just released (using DirectInput's Buffered Input).
	bool KeyReleasedEx(unsigned char ucDIKey); 

	//	Purpose	:	To get the ascii character value of the key the user typed.
	//				So they can enter letters.
	char CheckKeys(void);

	//	Purpose	:	To get the ascii character value of the key the user just typed.
	//				So they can enter letters (using DirectInput's Buffered Input).
	char CheckBufferedKeysEx(void);

	//	Purpose	:	To get the DIK code of the key the user is pressing.
	//				For key binding.
	unsigned char GetDIKCode(void);

	//	Purpose	:	To get the DIK code of the key the user just pressed.
	//				For key binding (using DirectInput's Buffered Input).
	unsigned char GetBufferedDIKCodeEx(void);

	///////////////////////////////////////////////////////////////////
	//						MOUSE								     //
	///////////////////////////////////////////////////////////////////

	//	Purpose	:	Gets the current (immediate) state of a mouse button.
	bool MouseButtonDown(unsigned char ucButton);

	//	Purpose	:	To tell if a mouse button was just pressed (without using DirectInput's Buffered Input).
	bool MouseButtonPressed(unsigned char ucButton);

	//	Purpose	:	To tell if a mouse button was just pressed (using DirectInput's Buffered Input).
	bool MouseButtonPressedEx(unsigned char ucButton);

	//	Purpose	:	Gets the current (immediate) state of a mouse button.
	bool MouseButtonUp(unsigned char ucButton);

	//	Purpose	:	To tell if a mouse button was just released (without using DirectInput's Buffered Input).
	bool MouseButtonReleased(unsigned char ucButton);

	//	Purpose	:	To tell if a mouse button was just released (using DirectInput's Buffered Input).
	bool MouseButtonReleasedEx(unsigned char ucButton);

	//	Purpose	:	To tell if a mouse button was just pressed (without using DirectInput's Buffered Input).
	int MouseCheckBufferedButtons(void);

	//	Purpose	:	To tell if a mouse button was just pressed (using DirectInput's Buffered Input).
	int MouseCheckBufferedButtonsEx(void);

	//	Purpose			:	To report the relative motion of the mouse 
	//						in the X dimension.
	long MouseMovementX(void);

	//	Purpose			:	To report the relative motion of the mouse 
	//						in the Y dimension.
	long MouseMovementY(void);

	//	Purpose			:	To report the relative motion of the mouse 
	//						wheel.
	long MouseWheelMovement(void);

	//	Purpose			:	To report the number of buttons on the device.
	int MouseGetNumButtons(void);

	//	Purpose			:	To help track the "psuedo" position of the mouse.
	int MouseGetPosX(void);

	//	Purpose			:	To help track the "psuedo" position of the mouse.
	int MouseGetPosY(void);

	//	Purpose			:	To set the "psuedo" position of the mouse.
	void MouseSetPosX(int nPosX);

	//	Purpose			:	To set the "psuedo" position of the mouse.
	void MouseSetPosY(int nPosY);

	///////////////////////////////////////////////////////////////////
	//						JOYSTICKS								 //
	///////////////////////////////////////////////////////////////////

	//	Purpose	:	Gets the current (immediate) state of a joystick button.
	bool JoystickButtonDown(unsigned char ucButton, int nJoyNum = 0);		
	
	//	Purpose	:	To tell if a joystick button was just pressed (using DirectInput's Buffered Input).
	bool JoystickButtonPressed(unsigned char ucButton, int nJoyNum = 0);	
	
	//	Purpose	:	To tell if a joystick button was just pressed (without using DirectInput's Buffered Input).
	bool JoystickButtonPressedEx(unsigned char ucButton, int nJoyNum = 0);

	//	Purpose	:	Gets the current (immediate) state of a joystick button.
	bool JoystickButtonUp(unsigned char ucButton, int nJoyNum = 0);		
	
	//	Purpose	:	To tell if a joystick button was just released (using DirectInput's Buffered Input).
	bool JoystickButtonReleased(unsigned char ucButton, int nJoyNum = 0);	
	
	//	Purpose	:	To tell if a joystick button was just released (without using DirectInput's Buffered Input).
	bool JoystickButtonReleasedEx(unsigned char ucButton, int nJoyNum = 0);

	///////////////////////////////////////////////////////////////////
	//	D-pad:
	///////////////////////////////////////////////////////////////////

	//	Purpose	:	To tell if a D-pad direction is down.
	bool JoystickDPadDown(int nDir, int nJoyNum = 0); 
	
	//	Purpose	:	To get the (buffered) direction the D-pad was pressed (without using DirectInput's Buffered Input).
	bool JoystickDPadPressed(int nDir, int nJoyNum = 0);

	//	Purpose	:	To tell if a D-pad direction is up.
	bool JoystickDPadUp(int nDir, int nJoyNum = 0); 
	
	//	Purpose	:	To tell if a D-pad direction was just released (without using DirectInput's Buffered Input).
	bool JoystickDPadReleased(int nDir, int nJoyNum = 0);

	///////////////////////////////////////////////////////////////////
	//	Analog Sticks:
	///////////////////////////////////////////////////////////////////

	//	L-stick:
	//	Purpose	:	To get the (immediate) direction the stick is being held.
	bool JoystickGetLStickDirDown( int nDir, int nJoyNum = 0 );

	//	Purpose	:	To get the (buffered) direction the stick was pressed (without using DirectInput's Buffered Input).
	bool JoystickGetLStickDirPressed( int nDir, int nJoyNum = 0 );

	//	Purpose	:	To get the position of the joystick in a digital range.
	int JoystickGetLStickXAmount( int nJoyNum = 0 );
	
	//	Purpose	:	To get the position of the joystick in a digital range.
	int JoystickGetLStickYAmount( int nJoyNum = 0 );

	//	Purpose	:	To get the position of the joystick in a normalized range.
	float JoystickGetLStickXNormalized( int nJoyNum = 0 );

	//	Purpose	:	To get the position of the joystick in a normalized range.
	float JoystickGetLStickYNormalized( int nJoyNum = 0 );

	//  R-stick:
	//	Purpose	:	To get the (immediate) direction the stick is being held.
	bool JoystickGetRStickDirDown( int nDir, int nJoyNum = 0 );

	//	Purpose	:	To get the (buffered) direction the stick was pressed (without using DirectInput's Buffered Input).
	bool JoystickGetRStickDirPressed( int nDir, int nJoyNum = 0 );
	
	//	Purpose	:	To get the position of the joystick in a digital range.
	int JoystickGetRStickXAmount( int nJoyNum = 0 );

	//	Purpose	:	To get the position of the joystick in a digital range.
	int JoystickGetRStickYAmount( int nJoyNum = 0 );

	//	Purpose	:	To get the position of the joystick in a normalized range.
	float JoystickGetRStickXNormalized( int nJoyNum = 0 );
	
	//	Purpose	:	To get the position of the joystick in a normalized range.
	float JoystickGetRStickYNormalized( int nJoyNum = 0 );

	///////////////////////////////////////////////////////////////////
	//	Triggers:
	///////////////////////////////////////////////////////////////////

	//	Purpose	:	To get the position of the trigger in a digital range.
	int JoystickGetLTriggerAmount( int nJoyNum = 0 );

	//	Purpose	:	To get the position of the trigger in a digital range.
	int JoystickGetRTriggerAmount( int nJoyNum = 0 );

	//	Purpose	:	To get the position of the trigger in a normalized range.
	float JoystickGetLTriggerNormalized( int nJoyNum = 0 );

	//	Purpose	:	To get the position of the trigger in a normalized range.
	float JoystickGetRTriggerNormalized( int nJoyNum = 0 );

	//	Purpose	:	To tell which joystick button was just pressed (without using DirectInput's Buffered Input).
	int	JoystickCheckBufferedButtons( int nJoyNum = 0 );

	//	Purpose	:	To tell which joystick button was just pressed (using DirectInput's Buffered Input).
	int	JoystickCheckBufferedButtonsEx( int nJoyNum = 0 );

	//	Purpose			:	To report the number of buttons on the device.
	int JoystickGetNumButtons( int nJoyNum = 0 ) const;

	//	Purpose	:	Returns the true if the joystick is unplugged.
	bool JoystickIsUnplugged( int nJoyNum = 0 ) const;

	//	Purpose	:	Returns the name of the joystick (i.e. "Logitech RumblePad 2 USB")
	const TCHAR* JoystickGetName( int nJoyNum = 0 ) const;

	//	Purpose	:	To swap the X/Y axes of certain controllers.
	void JoystickSwapRStickAxes( bool bSwapAxes, int nJoyNum = 0 );
};

//	Interface class defining "blue print" functions.
const int g_knBUFFER_SIZE = 10;	//	Arbitrary number of elements for Buffered Input.
class InterfaceDirectInputDevice
{
public:
	virtual ~InterfaceDirectInputDevice( void ) = 0 {};

	virtual bool ReadDevice( void ) = 0;
	virtual bool ReadBufferedDevice( void ) = 0;
	
	virtual bool Acquire( void ) = 0;
	virtual bool Unacquire( void ) = 0;
};

class DirectInputDevice : public InterfaceDirectInputDevice
{
protected:
	LPDIRECTINPUTDEVICE8	m_lpDevice;					//	DirectInput Device pointer.
	
	//	For DirectX Buffered input:
	DIDEVICEOBJECTDATA		m_didod[g_knBUFFER_SIZE];	//	Receives buffered data for the device.
	DWORD					m_dwBufferElements;			//	Number of element in the buffer for the device.

	//	Utility function to clear buffered data.
	void ClearBufferedData(void)
	{
		memset(&m_didod, 0, sizeof(m_didod));	//	clear out device object data.
		m_dwBufferElements = g_knBUFFER_SIZE;	//	set buffer elements to the size of the array.
	}

public:
	//	Constructor.
	DirectInputDevice( void )
	{
		m_lpDevice = NULL;

		ClearBufferedData();
	}

	//	Destructor.
	virtual ~DirectInputDevice(void)
	{
		if ( m_lpDevice )
		{
			m_lpDevice->Unacquire();
			Safe_Release( m_lpDevice );
		}
	}

	//	Purpose	:	Gets the DirectInput Buffered Data.
	virtual bool ReadBufferedDevice(void)
	{
		//	Make sure the device was made.
		if (!m_lpDevice)
			return false;

		ClearBufferedData();

		//	Attempt to read the device...
		if (FAILED( m_lpDevice->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), m_didod, &m_dwBufferElements, 0) ))
		{
			//	If we couldn't, try to re-acquire the device.
			if (FAILED( m_lpDevice->Acquire() ))
				return false; //	Could not re-acquire the Device.

			ClearBufferedData();

			//	Now try reading it
			if (FAILED( m_lpDevice->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), m_didod, &m_dwBufferElements, 0) ))
				return false;
		}

		//	Success
		return true;
	}
	
	//	returns true if the device was able to be acquired.
	virtual bool Acquire( void )	{ return (m_lpDevice) ? SUCCEEDED( m_lpDevice->Acquire() ) : false; }

	//	returns true if the device was able to be unacquired.
	virtual bool Unacquire( void )	{ return (m_lpDevice) ? SUCCEEDED( m_lpDevice->Unacquire() ) : false; }

};

//////////////////////////////////////////////////////////////////////////////////
//	Keyboard Class
//////////////////////////////////////////////////////////////////////////////////
class DIKeyboard : public DirectInputDevice
{
private:
	unsigned char		m_ucKeysPressed[256];			//	Holds Keyboard Data.
	unsigned char		m_ucPrevKeysPressed[256];		//	Used for BufferedKeyEx.

	unsigned char		m_ucAsciiVals[256];		//	For CheckKeys and CheckBufferedKeys.
	HKL					m_keyLayout;			//	For CheckKeys and CheckBufferedKeys.



public:
	//	Purpose	:	Clear the state of the keys. 
	void ClearKeys(void)	
	{ 
		//	clear the currently pressed keys
		memset(m_ucKeysPressed, 0, 256 * sizeof(unsigned char)); 
		//	clear the previously pressed keys
		memset(m_ucPrevKeysPressed, 0, 256 * sizeof(unsigned char));
	}

	//	Purpose	:	Setup the keyboard for use with DirectInput.
	DIKeyboard(LPDIRECTINPUT8 pDI, HWND hWnd, bool bIsExclusive=false);
	
	//	Purpose	:	Reads the state of the device.
	bool ReadDevice(void);

	//	Purpose	:	Gets the DirectInput Buffered Data.
	bool ReadBufferedDevice(void);

	//	Purpose	:	To acquire the device when the application gains focus.
	bool Acquire(void)		{ ClearKeys(); return DirectInputDevice::Acquire(); }
	
	//	Purpose	:	To unacquire the device when the application loses focus.

	bool Unacquire(void)	{ ClearKeys(); return DirectInputDevice::Unacquire();  }

	//	Purpose	:	Gets the current (immediate) state of a Key.
	bool KeyDown(unsigned char ucDIKey);
	
	//	Purpose	:	To tell if a key was just pressed (without using DirectInput's Buffered Input).
	bool KeyPressed(unsigned char ucDIKey);
	
	//	Purpose	:	To tell if a key was just pressed (using DirectInput's Buffered Input).
	bool KeyPressedEx(unsigned char ucDIKey); // was key just pressed?

	//	Purpose	:	Gets the current (immediate) state of a Key.
	bool KeyUp(unsigned char ucDIKey);
	
	//	Purpose	:	To tell if a key was just released (without using DirectInput's Buffered Input).
	bool KeyReleased(unsigned char ucDIKey); 

	//	Purpose	:	To tell if a key was just released (using DirectInput's Buffered Input).
	bool KeyReleasedEx(unsigned char ucDIKey);

	//	Purpose	:	To get the ascii character value of the key the user typed.
	//				So they can enter letters.
	char CheckKeys(void);

	//	Purpose	:	To get the ascii character value of the key the user just typed.
	//				So they can enter letters (using DirectInput's Buffered Input).
	char CheckBufferedKeysEx(void);

	//	Purpose	:	To get the DIK code of the key the user is pressing.
	//				For key binding.
	unsigned char GetDIKCode(void);

	//	Purpose	:	To get the DIK code of the key the user just pressed.
	//				For key binding (using DirectInput's Buffered Input).
	unsigned char GetBufferedDIKCodeEx(void);

};

//////////////////////////////////////////////////////////////////////////////////
//	Mouse Class
//////////////////////////////////////////////////////////////////////////////////
class DIMouse : public DirectInputDevice
{
private:
	DIMOUSESTATE2	m_diMouseState;			//	Holds Mouse Data (button and movement info).
	DIMOUSESTATE2	m_diPrevMouseState;		//	Holds the previous state.
	
	int				m_nNumButtons;			//	Number of buttons supported.

	int				m_nPosX;				//	Helper positions for mouse cursor.
	int				m_nPosY;			

public:

	//	Purpose	:	Clear the state of the buttons. 
	void ClearMouseButtons(void)	
	{ 
		//	clear the currently pressed keys
		memset(m_diMouseState.rgbButtons, 0, 8*sizeof(BYTE)); 
		//	clear the previously pressed keys
		memset(m_diPrevMouseState.rgbButtons, 0, 8*sizeof(BYTE));
	}

	//	Purpose	:	Setup the mouse for use with DirectInput.
	DIMouse(LPDIRECTINPUT8 pDI, HWND hWnd, bool bIsExclusive=false);

	//	Purpose	:	Reads the state of the device every frame.
	bool ReadDevice(void);

	//	Purpose	:	Gets the DirectInput Buffered Data.
	bool ReadBufferedDevice(void);
	
	//	Purpose	:	Gets the current (immediate) state of a mouse button.
	bool ButtonDown(unsigned char ucButton);

	//	Purpose	:	To tell if a mouse button was just pressed (without using DirectInput's Buffered Input).
	bool ButtonPressed(unsigned char ucButton);
	
	//	Purpose	:	To tell if a mouse button was just pressed (using DirectInput's Buffered Input).
	bool ButtonPressedEx(unsigned char ucButton);

	//	Purpose	:	Gets the current (immediate) state of a mouse button.
	bool ButtonUp(unsigned char ucButton);

	//	Purpose	:	To tell if a mouse button was just released (without using DirectInput's Buffered Input).
	bool ButtonReleased(unsigned char ucButton);

	//	Purpose	:	To tell if a mouse button was just released (using DirectInput's Buffered Input).
	bool ButtonReleasedEx(unsigned char ucButton);

	//	Purpose	:	To tell if a mouse button was just pressed (without using DirectInput's Buffered Input).
	int CheckBufferedButtons(void);

	//	Purpose	:	To tell if a mouse button was just pressed (using DirectInput's Buffered Input).
	int	CheckBufferedButtonsEx(void);

	//	Purpose			:	To report the relative motion of the mouse 
	//						in the X dimension.
	long MovementX(void);

	//	Purpose			:	To report the relative motion of the mouse 
	//						in the Y dimension.
	long MovementY(void);

	//	Purpose			:	To report the relative motion of the mouse 
	//						wheel.
	long WheelMovement(void);

	//	Purpose			:	To report the number of buttons on the device.
	int GetNumButtons(void)		{ return m_nNumButtons; }

	//	Purpose			:	To help track the "psuedo" position of the mouse.
	int GetPosX(void)			{ return m_nPosX; }

	//	Purpose			:	To help track the "psuedo" position of the mouse.
	int GetPosY(void)			{ return m_nPosY; }

	//	Purpose			:	To set the "psuedo" position of the mouse.
	void SetPosX(int nPosX)			{ m_nPosX = nPosX; }

	//	Purpose			:	To set the "psuedo" position of the mouse.
	void SetPosY(int nPosY)			{ m_nPosY = nPosY; }

};

//////////////////////////////////////////////////////////////////////////////////
//	Joysticks Class
//////////////////////////////////////////////////////////////////////////////////
class DIJoystick : public DirectInputDevice
{
private:
	TCHAR			m_szJoyName[ MAX_PATH ];		//	Holds the product name of the joystick.
	
	DIJOYSTATE2		m_diJoyState;				//	Holds Joystick Data (button and movement info).
	DIJOYSTATE2		m_diPrevJoyState;			//	Holds the previous state.

	int				m_nNumButtons;				//	Number of buttons supported.
	bool			m_bIsUnplugged;				//	Tracks if the joystick is currently unplugged.

	bool			m_bIsXbox360Pad;			//	Tracks if it is an Xbox360 pad.
	bool			m_bIsZAxisY;				//	Swaps whether Z or RotationZ is considered the Y-Axis.

	// POV constants
	enum POV_dirs
	{ 
		POV_NEUTRAL		=  -1,
		POV_UP			=   0,
		POV_UPRIGHT		=  45 * DI_DEGREES, 
		POV_RIGHT		=  90 * DI_DEGREES,
		POV_DOWNRIGHT	= 135 * DI_DEGREES,
		POV_DOWN		= 180 * DI_DEGREES,
		POV_DOWNLEFT	= 225 * DI_DEGREES,
		POV_LEFT		= 270 * DI_DEGREES,
		POV_UPLEFT		= 315 * DI_DEGREES
	};

	//	Utility functions:

	//	Purpose	:	Translates a checked for direction from a numerical mess.
	bool TranslatePOV(int nDir, DWORD dwPOVDir);

	//	Purpose	:	To get the position of the joystick in a digital range.
	LONG TranslateRStickX(DIJOYSTATE2& diJoyState);

	//	Purpose	:	To get the position of the joystick in a digital range.
	LONG TranslateRStickY(DIJOYSTATE2& diJoyState);

public:
	//	Purpose	:	Clear the state of the buttons. 
	void ClearJoystickButtons(void)	
	{ 
		//	clear the currently pressed keys
		memset(m_diJoyState.rgbButtons, 0, 128*sizeof(BYTE)); 
		//	clear the previously pressed keys
		memset(m_diPrevJoyState.rgbButtons, 0, 128* sizeof(BYTE));
	}
	
	//	Purpose	:	Setup the joystick for use with DirectInput.
	DIJoystick(LPDIRECTINPUT8 pDI, HWND hWnd, const DIDEVICEINSTANCE* lpdidi, bool bIsExclusive=false);

	//	Purpose	:	Reads the state of the device.
	bool ReadDevice(void);

	//	Purpose	:	Gets the DirectInput Buffered Data.
	bool ReadBufferedDevice(void);

	//	Purpose	:	Toggles whether the Z or RotationZ axis is considered the Y Axis.
	void SwitchRStickAxes(void);

	///////////////////////////////////////////////////////////////////
	//	Buttons:
	///////////////////////////////////////////////////////////////////

	//	Purpose	:	Gets the current (immediate) state of a joystick button.
	bool ButtonDown(unsigned char ucButton);

	//	Purpose	:	To tell if a joystick button was just pressed (without using DirectInput's Buffered Input).
	bool ButtonPressed(unsigned char ucButton);
	
	//	Purpose	:	To tell if a joystick button was just pressed (using DirectInput's Buffered Input).
	bool ButtonPressedEx(unsigned char ucButton);

	//	Purpose	:	Gets the current (immediate) state of a joystick button.
	bool ButtonUp(unsigned char ucButton);

	//	Purpose	:	To tell if a joystick button was just released (without using DirectInput's Buffered Input).
	bool ButtonReleased(unsigned char ucButton);

	//	Purpose	:	To tell if a joystick button was just released (using DirectInput's Buffered Input).
	bool ButtonReleasedEx(unsigned char ucButton);

	///////////////////////////////////////////////////////////////////
	//	D-pad:
	///////////////////////////////////////////////////////////////////

	//	Purpose	:	To tell if a D-pad direction is down.
	bool DPadDown(int nDir); 

	//	Purpose	:	To get the (buffered) direction the D-pad was pressed (without using DirectInput's Buffered Input).
	bool DPadPressed(int nDir);

	//	Purpose	:	To tell if a D-pad direction is up.
	bool DPadUp(int nDir); 

	//	Purpose	:	To tell if a D-pad direction was just released (without using DirectInput's Buffered Input).
	bool DPadReleased(int nDir);

	///////////////////////////////////////////////////////////////////
	//	Analog Sticks:
	///////////////////////////////////////////////////////////////////
	
	//	L-stick:
	//	Purpose	:	To get the (immediate) direction the stick is being held.
	bool GetLStickDirDown(int nDir);

	//	Purpose	:	To get the (buffered) direction the stick was pressed (without using DirectInput's Buffered Input).
	bool GetLStickDirPressed(int nDir);

	//	Purpose	:	To get the position of the joystick in a digital range.
	int GetLStickXAmount(void);

	//	Purpose	:	To get the position of the joystick in a digital range.
	int GetLStickYAmount(void);

	//	Purpose	:	To get the position of the joystick in a normalized range.
	float GetLStickXNormalized();

	//	Purpose	:	To get the position of the joystick in a normalized range.
	float GetLStickYNormalized();

	//  R-stick:
	//	Purpose	:	To get the (immediate) direction the stick is being held.
	bool GetRStickDirDown(int nDir);

	//	Purpose	:	To get the (buffered) direction the stick was pressed (without using DirectInput's Buffered Input).
	bool GetRStickDirPressed(int nDir);

	//	Purpose	:	To get the position of the joystick in a digital range.
	int GetRStickXAmount(void);

	//	Purpose	:	To get the position of the joystick in a digital range.
	int GetRStickYAmount(void);

	//	Purpose	:	To get the position of the joystick in a normalized range.
	float GetRStickXNormalized(void);

	//	Purpose	:	To get the position of the joystick in a normalized range.
	float GetRStickYNormalized(void);

	//	Purpose	:	To get the position of the trigger in a digital range.
	int GetLTriggerAmount(void);

	//	Purpose	:	To get the position of the trigger in a digital range.
	int GetRTriggerAmount(void);

	//	Purpose	:	To get the position of the trigger in a normalized range.
	float GetLTriggerNormalized(void);

	//	Purpose	:	To get the position of the trigger in a normalized range.
	float GetRTriggerNormalized(void);

	//	Purpose	:	To tell which joystick button was just pressed (without using DirectInput's Buffered Input).
	int	CheckBufferedButtons(void);

	//	Purpose	:	To tell which joystick button was just pressed (using DirectInput's Buffered Input).
	int	CheckBufferedButtonsEx(void);

	//	Purpose			:	To report the number of buttons on the device.
	int GetNumButtons(void)	const			{ return m_nNumButtons; }

	//	Purpose	:	Returns the true if the joystick is unplugged.
	bool IsUnplugged(void) const		{ return m_bIsUnplugged; }

	//	Purpose	:	Returns the name of the joystick (i.e. "Logitech RumblePad 2 USB")
	const TCHAR* GetName(void) const		{ return (const TCHAR*)m_szJoyName; }

	//	Purpose	:	To swap the X/Y axes of certain controllers.
	void SwapRStickAxes(bool bSwapAxes)	{ m_bIsZAxisY = bSwapAxes; }

};